(function(w) {
    var eyeFactory = (function() {
        // eyeTools object constructor
        var eyeTools = function eyeTools(config) {
            // private variables
            var _ = {
                baseRadius : 10, // 基础半径
                element : null, // 绘制区域(热点图传div,其它传canvas)
                datapoints : [], // 数据点集合
                colors : "0,0,255", // 颜色集合(仅对轨迹图有效)
                maxRadiusSize : 200, // 最大圆半径大小(仅对轨迹图有效,该参数暂时未使用)
                deviation : 30, // 包含偏离范围大小(仅对轨迹图、热点图有效)
                diaphaneity : 0.2, // 透明度
                worker : 1,// 多线程并发数(即待画图的被试个数)
                heatMapContainer : [], // 热点图容器(清除热点图时需要)
                heatMapMaxScale : 1.8, // 热点图最大值等级
                routeSizeDrawCount : 15, // 轨迹图同一区域包含多少个点才绘制
                routeCurrentNumber : [], // 轨迹图当前编号
                routeRadiusType : 1, // 轨迹图圆圈绘制类型
                routeMapDataSourceType : 1, // 轨迹图数据源类型
                routeAlterableRadius : 1, // 轨迹图按注视时间绘制时的半径
                focusShadowBlur : 15, // 焦点图阴影羽化等级
                drawFirstPoint : [], // 是否绘制第一个点(仅对动态轨迹图有效)
                routeIsDrawNumber : 1
            // 轨迹图是否绘制数字: 1绘制(默认),-1不绘制
            };

            this.get = function(key) {
                return _[key];
            };
            this.set = function(key, value) {
                _[key] = value;
            };

            /**
             * 颜色转换函数(16进制色->RGB色)
             */
            this.convertColor = function(hexColor) {
                if (hexColor == null || hexColor == '') {
                    return null;
                }

                if (hexColor.length == 4 || hexColor.length == 7) {
                    var result = "";

                    if (hexColor.length == 7) {
                        for ( var i = 0; i < hexColor.length;) {
                            var c = hexColor.charAt(i);
                            if (c == '#') {
                                i++;
                                continue;
                            }
                            var val = hexColor.substring(i, (i + 2));

                            if ((i + 2) == hexColor.length) {
                                result += parseInt("0x" + val);
                            } else {
                                result += parseInt("0x" + val) + ',';
                            }
                            i = i + 2;
                        }
                    } else {
                        for ( var i = 0; i < hexColor.length; i++) {
                            var c = hexColor.charAt(i);
                            if (c == '#') {
                                continue;
                            }

                            if ((i + 1) == hexColor.length) {
                                result += parseInt("0x" + c + c);
                            } else {
                                result += parseInt("0x" + c + c) + ',';
                            }
                        }
                    }
                    return result;
                }
                return null;
            };

            /**
             * 公共绘制轨迹图方法(绘制、播放通用)
             */
            this.commonDrawRouteMap = function(context2D, color, routeRadiusType, baseRadius, routeAlterableRadius, diaphaneity, newObjs, prePoint, startIndex, currentNumber, routeIsDrawNumber) {
                // prePoint表示前一点,startIndex表示起始遍历序号
                for ( var i = startIndex; i < newObjs.length; i++) {
                    var drawX = newObjs[i].x;
                    var drawY = newObjs[i].y;

                    /** 计算半径大小 */
                    var radius = baseRadius;
                    if (routeRadiusType == 1) { // 根据注视时间,以500ms为单位绘制
                        if (newObjs[i].fixDur >= 500) {
                            radius = routeAlterableRadius; // 最大值不超过baseRadius
                        } else {
                            radius = (routeAlterableRadius * newObjs[i].fixDur) / 500;
                        }
                    }

                    var g2 = context2D.createRadialGradient(drawX, drawY, 5, drawX, drawY, radius);
                    g2.addColorStop(1, 'rgba(' + color + ',' + diaphaneity + ')');

                    /** 画圆和线 */
                    context2D.beginPath();
                    context2D.fillStyle = g2;
                    context2D.arc(drawX, drawY, radius, 0, 2 * Math.PI);
                    context2D.fill();

                    /** 填充数字 */
                    if (routeIsDrawNumber == 1) {
                        context2D.beginPath();
                        context2D.fillStyle = "#646464";
                        context2D.font = "12px arial";
                        context2D.textBaseline = 'center';
                        context2D.fillText((i + currentNumber), drawX - 4, drawY + 6); // currentNumber为在圆圈中填充的数字
                    }

                    if (prePoint.x != -1 && prePoint.y != -1) {
                        context2D.beginPath();
                        context2D.moveTo(prePoint.x, prePoint.y);
                        context2D.lineWidth = "1";
                        context2D.strokeStyle = 'rgba(' + color + ',' + diaphaneity + ')';
                        context2D.lineTo(drawX, drawY);
                        context2D.stroke();
                    }

                    prePoint = {
                        x : drawX,
                        y : drawY
                    };
                }
            };

            // configure the eyeTools when an instance gets created
            this.configure(config);
            // and initialize it
            this.init();
        };

        // public functions
        eyeTools.prototype = {
            configure : function(config) {
                var me = this;
                // 初始化,若未设置则默认
                me.set("element", config.element);
                me.set("datapoints", config.datapoints || me.get("datapoints"));
                me.set("baseRadius", config.baseRadius || me.get("baseRadius"));
                me.set("maxRadiusSize", config.maxRadiusSize || me.get("maxRadiusSize"));
                me.set("deviation", config.deviation || me.get("deviation"));
                me.set("routeSizeDrawCount", config.routeSizeDrawCount || me.get("routeSizeDrawCount"));
                me.set("colors", config.colors || me.get("colors"));
                me.set("diaphaneity", config.diaphaneity || me.get("diaphaneity"));
                me.set("worker", config.worker || me.get("worker"));
                me.set("routeCurrentNumber", config.routeCurrentNumber || me.get("routeCurrentNumber"));
                me.set("routeRadiusType", config.routeRadiusType || me.get("routeRadiusType"));
                me.set("routeMapDataSourceType", config.routeMapDataSourceType || me.get("routeMapDataSourceType"));
                me.set("routeAlterableRadius", config.routeAlterableRadius || me.get("routeAlterableRadius"));
                me.set("drawFirstPoint", config.drawFirstPoint || me.get("drawFirstPoint"));
                me.set("routeIsDrawNumber", config.routeIsDrawNumber || me.get("routeIsDrawNumber"));
            },

            init : function() {
            },

            /**
             * 计算点是否包含
             * 
             * @param basepoint
             *            基础点
             * @param point
             *            是否被包含的点
             * @returns {Boolean}
             */
            contains : function(basepoint, point) {
                var me = this;
                var deviation = me.get("deviation");

                var distance = me.calcDistance(basepoint, point); // 获取两点之间的距离

                if (distance > deviation) {
                    return false;
                } else {
                    return true;
                }
            },

            /**
             * 计算两个点之间的距离
             * 
             * @param basepoint
             * @param point
             */
            calcDistance : function(basepoint, point) {
                var xLength = 0;
                var yLength = 0;

                if (basepoint.x > point.x) {
                    xLength = basepoint.x - point.x;
                } else {
                    xLength = point.x - basepoint.x;
                }

                if (basepoint.y > point.y) {
                    yLength = basepoint.y - point.y;
                } else {
                    yLength = point.y - basepoint.y;
                }

                var distance = Math.sqrt(xLength * xLength + yLength * yLength); // 勾股定理算两点直接距离

                return distance;

            },

            /**
             * 过滤处理轨迹图数据 (已停止使用)
             * 
             * @param points
             * @returns {Array}
             */
            filterRouteData : function(points) {
                var me = this;
                var deviation = me.get("deviation");
                var basePoint = null;
                var newDataSet = new Array();
                var count = 0; // 最多出现次数
                var maxDistance = 0; // 最大间隔距离
                var distance = 0; // 两点距离临时变量
                var averagePoint = null; // 平均点,由于计算一个范围内所有点的平均坐标

                for ( var i = 0; i < points.length; i++) {
                    basePoint = points[i];
                    averagePoint = points[i];

                    // 从当前i的下一点开始
                    for ( var j = i + 1; j < points.length; j++) {
                        i = j - 1; // 由于for循环中后续要执行i++,而下一循环需从j开始,因此i=j-1

                        distance = me.calcDistance(basePoint, points[j]); // 此处不使用封装的contain函数，是因为两点距离后续需要
                        if (distance <= deviation) { // 距离小于等于偏差,则包含
                            count++; // 出现次数自增

                            if (distance > maxDistance) { // 赋予最大间距
                                maxDistance = distance;
                            }

                            // 计算平均坐标
                            averagePoint.x = (averagePoint.x + points[j].x) / 2;
                            averagePoint.y = (averagePoint.y + points[j].y) / 2;

                        } else {
                            break;
                        }
                    }
                    if (count >= me.get("routeSizeDrawCount")) {
                        newDataSet.push({
                            x : averagePoint.x,
                            y : averagePoint.y,
                            count : count,
                            radius : maxDistance,
                            time : basePoint.time
                        });
                    }
                    count = 0;
                }

                return newDataSet;
            },

            /**
             * 过滤处理热点图数据 过滤策略：按偏差范围,计算每个点的出现次数。 (已停止使用)
             * 
             * @param points
             * @returns {Array}
             */
            filterHeatData : function(points) {
                var me = this;
                var basePoint = null;
                var newDataSet = new Array();
                var hadFlag = false;

                for ( var i = 0; i < points.length; i++) {
                    basePoint = points[i];

                    hadFlag = false;
                    for ( var j = 0; j < newDataSet.length; j++) {
                        if (me.contains(newDataSet[j], basePoint)) {
                            hadFlag = true; // 该点已经被计算过,则直接加1
                            newDataSet[j].count++;

                            // 计算平均坐标
                            newDataSet[j].averageX = (newDataSet[j].averageX + basePoint.x) / 2;
                            newDataSet[j].averageY = (newDataSet[j].averageY + basePoint.y) / 2;

                            break;
                        }
                    }
                    if (hadFlag) { // 如果已被计算,则跳过该点
                        continue;
                    }

                    newDataSet.push({
                        x : basePoint.x,
                        y : basePoint.y,
                        averageX : basePoint.x,
                        averageY : basePoint.y,
                        count : 1
                    });
                }

                for ( var j = 0; j < newDataSet.length; j++) { // 将点置为平均坐标
                    newDataSet[j].x = newDataSet[j].averageX;
                    newDataSet[j].y = newDataSet[j].averageY;
                }
                return newDataSet;
            },

            /**
             * 画单个轨迹图
             * 
             * @param idx
             */
            drawRouteMap : function(idx) {
                var me = this;
                var context2D = me.get("element")[0].getContext("2d");
                var objs = [], color = "";
                var diaphaneity = me.get("diaphaneity");
                var routeRadiusType = me.get("routeRadiusType");
                var baseRadius = me.get("baseRadius");
                var routeAlterableRadius = me.get("routeAlterableRadius");
                var routeIsDrawNumber = me.get("routeIsDrawNumber");

                if (!isNaN(idx)) {
                    objs = me.get("datapoints")[idx];
                    color = me.get("colors")[idx];
                } else {
                    objs = eval(me.get("datapoints"));
                    color = me.get("colors");
                }
                color = me.convertColor(color);

                var newObjs = newPointModel(objs);

                var prePoint = {
                    x : -1,
                    y : -1
                };

                var startIndex = 0; // 直接绘制从0开始
                var currentNumber = 1; // 直接绘制圆圈数值从1开始

                me.commonDrawRouteMap(context2D, color, routeRadiusType, baseRadius, routeAlterableRadius, diaphaneity, newObjs, prePoint, startIndex, currentNumber, routeIsDrawNumber);

            },

            /**
             * 画单个轨迹图(基于原始数据)
             * 
             * @param idx
             */
            drawRouteMap_RawData : function(idx) {
                var me = this;
                var context2D = me.get("element")[0].getContext("2d");
                var objs = [], color = "";
                var diaphaneity = me.get("diaphaneity");

                if (!isNaN(idx)) {
                    objs = me.get("datapoints")[idx];
                    color = me.get("colors")[idx];
                } else {
                    objs = eval(me.get("datapoints"));
                    color = me.get("colors");
                }
                color = me.convertColor(color);

                var newObjs = newPointModel(objs);
                var prePoint = {
                    x : -1,
                    y : -1
                };

                for ( var i = 0; i < newObjs.length; i++) {
                    var drawX = newObjs[i].x;
                    var drawY = newObjs[i].y;

                    if (i == (newObjs.length - 1)) { //原始数据只绘制最后一个点的圆形
                        var radius = 15; // 圆大小直接默认
                        var g2 = context2D.createRadialGradient(drawX, drawY, 5, drawX, drawY, radius);
                        g2.addColorStop(1, 'rgba(' + color + ',' + diaphaneity + ')');

                        /** 画圆和线 */
                        context2D.beginPath();
                        context2D.fillStyle = g2;
                        context2D.arc(drawX, drawY, radius, 0, 2 * Math.PI);
                        context2D.fill();
                    }

                    if (prePoint.x != -1 && prePoint.y != -1) {
                        context2D.beginPath();
                        context2D.moveTo(prePoint.x, prePoint.y);
                        context2D.lineWidth = "2";
                        context2D.strokeStyle = 'rgba(' + color + ',' + diaphaneity + ')';
                        context2D.lineTo(drawX, drawY);
                        context2D.stroke();
                    }

                    prePoint = {
                        x : drawX,
                        y : drawY
                    };
                }

            },

            /**
             * 画多个轨迹图
             */
            multDrawRouteMap : function() {
                var me = this;
                var routeMapDataSourceType = me.get("routeMapDataSourceType");
                for ( var j = 0; j < me.get("worker"); j++) {
                    if (routeMapDataSourceType == 1) {
                        me.drawRouteMap(j);
                    } else {
                        me.drawRouteMap_RawData(j);
                    }
                }
            },

            /**
             * 画单个焦点图
             * 
             * @param idx
             */
            drawFocusMap : function(idx) {
                var me = this;
                var context2D = me.get("element")[0].getContext("2d");
                var objs = [];
                var baseRadius = me.get("baseRadius");
                var focusShadowBlur = me.get("focusShadowBlur");

                if (!isNaN(idx)) {
                    objs = me.get("datapoints")[idx];
                } else {
                    objs = eval(me.get("datapoints"));
                }

                var newObjs = newPointModel(objs);

                for ( var i = 0; i < newObjs.length; i++) {
                    var drawX = newObjs[i].x;
                    var drawY = newObjs[i].y;

                    context2D.shadowColor = "#000000";// 阴影羽化
                    context2D.shadowBlur = focusShadowBlur;

                    context2D.globalCompositeOperation = 'destination-out';
                    context2D.beginPath();
                    context2D.arc(drawX, drawY, baseRadius, 0, Math.PI * 2, true);
                    context2D.closePath();
                    context2D.fill();
                }
            },

            /**
             * 画多个焦点图
             */
            multDrawFocusMap : function() {
                var me = this;

                for ( var j = 0; j < me.get("worker"); j++) {
                    me.drawFocusMap(j);
                }
            },

            /**
             * 画单个热点图
             * 
             * @param idx
             */
            drawHeatMap : function(idx) {
                var me = this;
                var heatMap = h337.create({
                    "element" : me.get("element")[0],
                    "radius" : me.get("baseRadius"),
                    "visible" : true
                });
                var objs = [], data = [], randomset = {};
                var max = 0;
                var maxCount = 0;

                me.get("heatMapContainer").push(heatMap);

                if (!isNaN(idx)) {
                    objs = me.get("datapoints")[idx];
                } else {
                    objs = eval(me.get("datapoints"));
                }

                var newObjs = newPointModel(objs);

                for ( var j = 0; j < newObjs.length; j++) {
                    data.push({
                        x : newObjs[j].x,
                        y : newObjs[j].y,
                        count : newObjs[j].fixDur
                    // 热点图效果，所有点的出现即是持续时间
                    });

                    // if (newObjs[j].fixDur > max) {
                    max += newObjs[j].fixDur;
                    maxCount++;
                    // }
                }
                randomset.max = (max / maxCount) * me.get("heatMapMaxScale"); // 热点最大值使用平均数
                randomset.data = data;

                heatMap.store.setDataSet(randomset);
            },

            /**
             * 画多个热点图
             * 
             * @param idx
             */
            multDrawHeatMap : function() {
                var me = this;

                var allPoints = new Array();
                for ( var i = 0; i < me.get("worker"); i++) {
                    var points = me.get("datapoints")[i];

                    for ( var j = 0; j < points.length; j++) {
                        allPoints.push(points[j]);
                    }
                }
                me.set("datapoints", allPoints);
                me.drawHeatMap();
            },

            /**
             * 清除热点图
             */
            clearHeatMap : function() {
                var me = this;

                var list = me.get("heatMapContainer");
                for ( var i = 0; i < list.length; i++) {
                    list[i].clear();
                    list[i].cleanup();
                }
                me.set("heatMapContainer", []);
            },

            /**
             * 播放单个轨迹图
             * 
             * @param idx
             */
            playRouteMap : function(idx) {
                var me = this;
                var context2D = me.get("element")[0].getContext("2d");
                var objs = [], color = "";
                var diaphaneity = me.get("diaphaneity");
                var routeRadiusType = me.get("routeRadiusType");
                var baseRadius = me.get("baseRadius");
                var routeAlterableRadius = me.get("routeAlterableRadius");
                var currentNumber = []; // 当前圆圈数值
                var drawFirstPoint = true;
                var routeIsDrawNumber = me.get("routeIsDrawNumber");

                if (!isNaN(idx)) {
                    objs = me.get("datapoints")[idx];
                    color = me.get("colors")[idx];
                    currentNumber = me.get("routeCurrentNumber")[idx];
                    drawFirstPoint = me.get("drawFirstPoint")[idx];
                } else {
                    objs = eval(me.get("datapoints"));
                    color = me.get("colors");
                    currentNumber = eval(me.get("routeCurrentNumber"));
                    drawFirstPoint = eval(me.get("drawFirstPoint"));
                }
                color = me.convertColor(color);

                var newObjs = newPointModel(objs);

                /** 设置起始序号 */
                var prePoint = { // 默认起始序号从0开始,没有上一点
                    x : -1,
                    y : -1
                };
                var startIndex = 0;

                if (!drawFirstPoint) { // 当不需要绘制第1点时,起始序号从1开始,上一点复制为第1点
                    prePoint = {
                        x : newObjs[0].x,
                        y : newObjs[0].y
                    };
                    startIndex = 1;
                }

                me.commonDrawRouteMap(context2D, color, routeRadiusType, baseRadius, routeAlterableRadius, diaphaneity, newObjs, prePoint, startIndex, currentNumber, routeIsDrawNumber);
            },

            /**
             * 播放多个轨迹图
             */
            multPlayRouteMap : function() {
                var me = this;
                for ( var j = 0; j < me.get("worker"); j++) {
                    me.playRouteMap(j);
                }
            }
        };

        return {
            create : function(config) {
                return new eyeTools(config);
            }
        };
    })();

    w.eyeTools = w.eyeFactory = eyeFactory;
})(window);
